#include <iostream>
#include <queue>
#include <pthread.h>
#include <ctime>
#include <sys/types.h> 
#include <unistd.h>
#include "BlockQueue.hpp"
#include "Task.hpp"
//阻塞队列类。 C：计算任务，S：存储任务
template <class C, class S>
struct BlockQueues
{
    BlockQueue<C> *c_bq;
    BlockQueue<S> *s_bq;
};
// 生产者跑这个函数，参与生产任务
void *productor(void *args)
{
    BlockQueue<CalTask>* bq = (static_cast<BlockQueues<CalTask, SaveTask>*>(args))->c_bq;//计算任务
    while (1)
    {
        // 生产数据
        int x = rand() % 10 + 1;
        int y = rand() % 5;
        int operCode = rand() % oper.size();
        CalTask t(x, y, oper[operCode], myMath);
        bq->push(t); // 把任务push进阻塞队列
        printf("Productor thread,生产计算任务：%s\n", t.toTaskString().c_str());
        sleep(1);
    }
    return nullptr;
}
// 消费者跑这个函数，参与计算任务和存储任务
void *consumer(void *args)
{
    BlockQueue<CalTask>* bq = (static_cast<BlockQueues<CalTask, SaveTask>*>(args))->c_bq;//计算任务
    //BlockQueue<SaveTask>* save_bq = (static_cast<BlockQueues<CalTask, SaveTask>*>(args))->s_bq;//存储任务

    while (1)
    {
        // 消费数据,计算任务
        CalTask t;
        bq->pop(&t);
        std::string result=t();
        printf("Cal thread,完成计算任务:%s...done\n", result.c_str());

        // //存储任务
        // SaveTask save(result,Save);
        // save_bq->push(save);//把save对象push进储存阻塞队列中
        // printf("Cal thread,推送存储任务完成\n");
        // //sleep(1);
    }
    return nullptr;
}

//储存线程跑这个函数，参与存储任务
void* saver(void* args)
{
    BlockQueue<SaveTask>* save_bq = (static_cast<BlockQueues<CalTask, SaveTask>*>(args))->s_bq;//拿到存储任务
    while(1)
    {
        SaveTask t;
        save_bq->pop(&t);
        t();//调用消费者类中的Save方法
        printf("save thread,保存任务完成...\n");
    }
    return nullptr;
}

int main()
{
    srand((unsigned int)time(nullptr) ^ getpid());
    BlockQueues<CalTask, SaveTask> bqs;
    // 两个阻塞队列
    bqs.c_bq = new BlockQueue<CalTask>();
    bqs.s_bq = new BlockQueue<SaveTask>();
    pthread_t c[2], p[3],s;//消费者、生产者、保存者线程
    pthread_create(c, nullptr, consumer, &bqs);
    pthread_create(c+1, nullptr, consumer, &bqs);

    pthread_create(p, nullptr, productor, &bqs);
    pthread_create(p+1, nullptr, productor, &bqs);
    pthread_create(p+2, nullptr, productor, &bqs);
    //pthread_create(&s, nullptr,saver ,&bqs);

    pthread_join(c[0], nullptr);
    pthread_join(c[1], nullptr);
    pthread_join(p[0], nullptr);
    pthread_join(p[1], nullptr);
    pthread_join(p[2], nullptr);
    //pthread_join(s, nullptr);
    delete bqs.c_bq;
    delete bqs.s_bq;
    return 0;
}